import type { Bounds, ShapeProperties } from './Shape';
import { Shape } from './Shape';

export class Rectangle extends Shape {
  public endX: number;
  public endY: number;

  constructor(
    x: number,
    y: number,
    color: string = 'blue',
    lineWidth: number = 2,
    stateProvider: Shape['stateProvider'],
  ) {
    super(x, y, color, lineWidth, stateProvider);
    this.endX = x;
    this.endY = y;
  }

  draw(ctx: CanvasRenderingContext2D): void {
    ctx.strokeStyle = this.color;
    ctx.lineWidth = this.lineWidth / this.stateProvider.getScale();
    ctx.beginPath();

    const left = Math.min(this.x, this.endX);
    const right = Math.max(this.x, this.endX);
    const top = Math.min(this.y, this.endY);
    const bottom = Math.max(this.y, this.endY);

    ctx.rect(left, -top, right - left, -(bottom - top));
    ctx.stroke();

    if (this.selected) {
      this.drawSelection(ctx);
    }
  }

  updateEnd(x: number, y: number): void {
    this.endX = x;
    this.endY = y;
  }

  contains(x: number, y: number): boolean {
    const left = Math.min(this.x, this.endX);
    const right = Math.max(this.x, this.endX);
    const top = Math.max(this.y, this.endY);
    const bottom = Math.min(this.y, this.endY);

    return x >= left && x <= right && y >= bottom && y <= top;
  }

  getProperties(): ShapeProperties {
    const left = Math.min(this.x, this.endX);
    const right = Math.max(this.x, this.endX);
    const top = Math.max(this.y, this.endY);
    const bottom = Math.min(this.y, this.endY);
    const width = right - left;
    const height = top - bottom;
    const centerX = (left + right) / 2;
    const centerY = (top + bottom) / 2;

    return {
      type: 'Rectangle',
      color: this.color,
      lineWidth: this.lineWidth,
      position: { x: this.x.toFixed(1), y: this.y.toFixed(1) },
      endPosition: { x: this.endX.toFixed(1), y: this.endY.toFixed(1) },
      dimensions: {
        width: width.toFixed(1),
        height: height.toFixed(1),
      },
      center: {
        x: centerX.toFixed(1),
        y: centerY.toFixed(1),
      },
      area: (width * height).toFixed(1),
    };
  }

  getBounds(): Bounds | null {
    return {
      left: Math.min(this.x, this.endX),
      right: Math.max(this.x, this.endX),
      top: Math.max(this.y, this.endY),
      bottom: Math.min(this.y, this.endY),
    };
  }

  updateSpecificProperty(prop: string, value: string): void {
    if (prop === 'x') {
      this.x = Number.parseFloat(value);
    } else if (prop === 'y') {
      this.y = Number.parseFloat(value);
    } else if (prop === 'endX') {
      this.endX = Number.parseFloat(value);
    } else if (prop === 'endY') {
      this.endY = Number.parseFloat(value);
    } else if (prop === 'width') {
      const currentWidth = Math.abs(this.endX - this.x);
      const newWidth = Number.parseFloat(value);
      const centerX = (this.x + this.endX) / 2;
      const halfWidth = newWidth / 2;
      this.x = centerX - halfWidth;
      this.endX = centerX + halfWidth;
    } else if (prop === 'height') {
      const currentHeight = Math.abs(this.endY - this.y);
      const newHeight = Number.parseFloat(value);
      const centerY = (this.y + this.endY) / 2;
      const halfHeight = newHeight / 2;
      this.y = centerY - halfHeight;
      this.endY = centerY + halfHeight;
    }
  }

  updateProperty(prop: string, value: string): void {
    super.updateProperty(prop, value);
    this.updateSpecificProperty(prop, value);
  }

  createAnchors(): void {
    const bounds = this.getBounds();
    if (!bounds) return;

    this.anchors = [
      { x: bounds.left, y: bounds.top, type: 'nw' },
      { x: bounds.right, y: bounds.top, type: 'ne' },
      { x: bounds.right, y: bounds.bottom, type: 'se' },
      { x: bounds.left, y: bounds.bottom, type: 'sw' },
      { x: (bounds.left + bounds.right) / 2, y: bounds.top, type: 'n' },
      { x: bounds.right, y: (bounds.top + bounds.bottom) / 2, type: 'e' },
      { x: (bounds.left + bounds.right) / 2, y: bounds.bottom, type: 's' },
      { x: bounds.left, y: (bounds.top + bounds.bottom) / 2, type: 'w' },
    ];
  }
}
